home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / drdobbs / 1990 / 11 / ayers.asc next >
Text File  |  1990-10-12  |  22KB  |  750 lines

  1. _THE MVC PARADIGMN AND SMALLTALK/V_
  2. by Kenneth E. Ayers
  3.  
  4. [LISTING ONE]
  5.  
  6. open
  7.     | frame |
  8.  
  9.     appName  := String new.
  10.     saved     := true.
  11.     editorPen := Pen new.
  12.     imagePen  := Pen new.
  13.     frame     := (Display boundingBox extent // 6)
  14.                    extent:(Display boundingBox extent * 2 // 3).
  15.     topPane := TopPane new
  16.         model:self;
  17.         label:self label;
  18.         menu:#windowMenu;
  19.         minimumSize:frame extent;
  20.         yourself.
  21.     topPane addSubpane:
  22.         (listPane := ListPane new
  23.             model:self;
  24.             name:#appList;
  25.             change:#appSelection:;
  26.             returnIndex:false;
  27.             menu:#listMenu;
  28.             framingRatio:(0 @ 0 extent:1/4 @ (2/3));
  29.             yourself).
  30.     topPane addSubpane:
  31.         (imagePane := GraphPane new
  32.             model:self;
  33.             name:#initImage:;
  34.             menu:#noMenu;
  35.             framingRatio:(0 @ (2/3) extent:1/4 @ (1/3));
  36.             yourself).
  37.     topPane addSubpane:
  38.         (editorPane := GraphPane new
  39.             model:self;
  40.             name:#initEditor:;
  41.             menu:#editorMenu;
  42.             change:#editIcon:;
  43.             framingRatio:(1/4 @ 0 extent:3/4 @ 1);
  44.             yourself).
  45.     topPane reframe:frame.
  46.     topPane dispatcher openWindow scheduleWindow.
  47.  
  48.  
  49. [LISTING TWO]
  50.  
  51. open
  52.     | frame listWid listHgt |
  53.  
  54.     saved     := true.
  55.     editorPen := Pen new.
  56.     imagePen  := Pen new.
  57.     frame     := (Display boundingBox extent // 6)
  58.                     extent:(Display boundingBox extent * 2 // 3).
  59.     listWid   := SysFont width * 10.
  60.     listHgt   := SysFont height * 10.
  61.  
  62.     topPane := TopPane new
  63.         label:self label;
  64.         model:self;
  65.         menu:#windowMenu;
  66.         minimumSize:frame extent;
  67.         yourself.
  68.     topPane addSubpane:
  69.         (listPane := ListPane new
  70.             model:self;
  71.             name:#appList;
  72.             change:#appSelection:;
  73.             returnIndex:false;
  74.             menu:#listMenu;
  75.             framingBlock:[:aFrame |
  76.                 aFrame origin
  77.                     extent:listWid @ listHgt];
  78.             yourself).
  79.     topPane addSubpane:
  80.         (imagePane := GraphPane new
  81.             model:self;
  82.             name:#initImage:;
  83.             menu:#noMenu;
  84.             framingBlock:[:aFrame|
  85.                 aFrame origin + (0 @ listHgt)
  86.                     extent:(listWid
  87.                            @ (aFrame height - listHgt))];
  88.             yourself).
  89.     topPane addSubpane:
  90.         (editorPane := GraphPane new
  91.             model:self;
  92.             name:#initEditor:;
  93.             menu:#editorMenu;
  94.             change:#editIcon:;
  95.             framingBlock:[:aFrame|
  96.                 aFrame origin + (listWid @ 0)
  97.                     extent:((aFrame width - listWid)
  98.                                    @ aFrame height)];
  99.             yourself).
  100.     topPane reframe:frame.
  101.  
  102.     topPane dispatcher openWindow scheduleWindow.
  103.  
  104.  
  105.  
  106. [COMPLETE SMALLTALK/V SOURCE KEN AYERS'S ARTICLE IN NOVEMBER 1990 ISSUE OF 
  107. DDJ]
  108.  
  109. [Listing -- Class EmptyMenu]
  110.  
  111. Menu subclass: #EmptyMenu
  112.   instanceVariableNames: ''
  113.   classVariableNames: ''
  114.   poolDictionaries: ''.
  115.  
  116. "***************************************************************"
  117. "**                EmptyMenu instance methods                 **"
  118. "***************************************************************"
  119.  
  120. popUpAt:aPoint
  121.         "An empty menu does nothing -- answer nil."
  122.     ^nil.
  123.  
  124. popUpAt:aPoint for:anObject
  125.         "An empty menu does nothing -- answer nil."
  126.     ^nil.
  127.  
  128.  
  129. [Listing -- Class IconEditor]
  130.  
  131. Object subclass: #IconEditor
  132.   instanceVariableNames: 
  133.     'scale cellSize cellOffset saved unZoom topPane listPane
  134.      editorPane imagePane iconLibrary iconName selectedIcon
  135.      gridForm editorPen imagePen'
  136.   classVariableNames: 
  137.     'IconSize '
  138.   poolDictionaries: 
  139.     'FunctionKeys CharacterConstants'.
  140.  
  141. "***************************************************************"
  142. "**                 IconEditor class methods                  **"
  143. "***************************************************************"
  144.  
  145. initialize
  146.         "Initialize the class variables."
  147.     IconSize isNil ifTrue:[IconSize := 32@32].
  148.  
  149. new
  150.         "Answer a new IconEditor."
  151.     self initialize.
  152.     ^super new.
  153.  
  154. "***************************************************************"
  155. "**                IconEditor instance methods                **"
  156. "***************************************************************"
  157.  
  158. "-----------------------------"
  159. "-- Window creation methods --"
  160. "-----------------------------"
  161.  
  162. openOn:anIconLibrary
  163.         "Open an IconEditor window on the Dictionary
  164.          anIconLibrary."
  165.     iconLibrary := anIconLibrary.
  166.     self open.
  167.  
  168. open
  169.         "Open an IconEditor window."
  170.     | frame |
  171.     iconLibrary isNil
  172.         ifTrue:[self initLibrary].
  173.     iconName  := String new.
  174.     saved     := true.
  175.     editorPen := Pen new.
  176.     imagePen  := Pen new.
  177.     frame     := (Display boundingBox extent // 6)
  178.                     extent:(Display boundingBox extent * 2 // 3).
  179.  
  180.     topPane := TopPane new
  181.         model:self;
  182.         label:self label;
  183.         menu:#windowMenu;
  184.         minimumSize:frame extent;
  185.         yourself.
  186.  
  187.     topPane addSubpane:
  188.         (listPane := ListPane new
  189.             model:self;
  190.             name:#iconList;
  191.             change:#iconSelection:;
  192.             returnIndex:false;
  193.             menu:#listMenu;
  194.             framingRatio:(0 @ 0 extent:1/4 @ (2/3));
  195.             yourself).
  196.  
  197.     topPane addSubpane:
  198.         (imagePane := GraphPane new
  199.             model:self;
  200.             name:#initImage:;
  201.             menu:#noMenu;
  202.             framingRatio:(0 @ (2/3) extent:1/4 @ (1/3));
  203.             yourself).
  204.  
  205.     topPane addSubpane:
  206.         (editorPane := GraphPane new
  207.             model:self;
  208.             name:#initEditor:;
  209.             menu:#editorMenu;
  210.             change:#editIcon:;
  211.             framingRatio:(1/4 @ 0 extent:3/4 @ 1);
  212.             yourself).
  213.  
  214.     topPane reframe:frame.
  215.     topPane dispatcher openWindow scheduleWindow.
  216.  
  217. "----------------------------"
  218. "-- Window support methods --"
  219. "----------------------------"
  220.  
  221. windowMenu
  222.         "Answer the menu for the IconEditor window."
  223.     ^Menu
  224.         labels:'collapse\cycle\frame\move\print\close' withCrs
  225.         lines:#(5)
  226.         selectors:#(collapse cycle resize
  227.                         printWindow move closeIt).
  228.  
  229. listMenu
  230.         "Answer the menu for the form list pane."
  231.     ^Menu
  232.         labels:'remove icon\create new icon\change size' withCrs
  233.         lines:#()
  234.         selectors:#(removeIt createIt resizeIt).
  235.  
  236. editorMenu
  237.         "Answer the menu for the Editor pane."
  238.     selectedIcon isNil ifTrue:[^EmptyMenu new].
  239.     ^Menu
  240.         labels:('invert\border\erase\save\print') withCrs
  241.         lines:#(3)
  242.         selectors:#(invertIt borderIt eraseIt saveIt printIcon).
  243.  
  244. noMenu
  245.         "Answer a do-nothing menu."
  246.     ^EmptyMenu new.
  247.  
  248. initEditor:aRect
  249.         "Inititalize the editor pane."
  250.     Display white:aRect.
  251.     ^Form new extent:aRect extent.
  252.  
  253. initImage:aRect
  254.         "Inititalize the IconEditor image pane."
  255.     Display white:aRect.
  256.     ^Form new extent:aRect extent.
  257.  
  258. iconList
  259.         "Answer a String Array containing the
  260.          names of the icons in the icon library."
  261.     ^iconLibrary keys asArray.
  262.  
  263. iconSelection:anIconName
  264.         "The user has selected anIconName from
  265.          the list.  Make it the selected icon
  266.          and re-initialize the editor."
  267.     | anIcon |
  268.     self saved ifFalse:[^self].
  269.     anIcon := iconLibrary at:anIconName ifAbsent:[nil].
  270.     anIcon isNil ifTrue:[^self].
  271.     selectedIcon := anIcon deepCopy.
  272.     iconName := anIconName.
  273.     selectedIcon extent = IconSize
  274.         ifTrue:[self displayIcon]
  275.         ifFalse:[
  276.             CursorManager execute change.
  277.             self resizeIt:selectedIcon extent].
  278.  
  279. editIcon:aPoint
  280.         "The select button has been pressed at aPoint.
  281.          If the cursor is in the editor image,
  282.          reverse that cell and all others that the
  283.          cursor passes over until the select button
  284.          is released."
  285.     | currX currY refX refY editing newX newY |
  286.     (editorPen clipRect containsPoint:Cursor offset)
  287.         ifFalse:[^self].
  288.     currX   := -1.
  289.     currY   := -1.
  290.     refX    := editorPen clipRect origin x.
  291.     refY    := editorPen clipRect origin y.
  292.     editing := true.
  293.     [editing]
  294.         whileTrue:[
  295.             newX := (Cursor offset x - refX) // scale.
  296.             newY := (Cursor offset y - refY) // scale.
  297.             ((newX = currX) and:[newY = currY])
  298.                 ifFalse:[
  299.                     currX := newX.
  300.                     currY := newY.
  301.                     self setX:currX Y:currY.
  302.                     saved := false].
  303.             editing :=
  304.                 (editorPen clipRect containsPoint:Cursor offset)
  305.                     and:[Terminal read ~= EndSelectFunction]].
  306.     selectedIcon
  307.         copy:imagePen clipRect
  308.         from:Display
  309.         to:0@0
  310.         rule:Form over.
  311.  
  312. "----------------------------"
  313. "-- Window control methods --"
  314. "----------------------------"
  315.  
  316. showWindow
  317.         "Redisplay the contents of the window's panes."
  318.     topPane collapsed
  319.         ifFalse:[self displayIcon].
  320.  
  321. activatePane
  322.         "If the cursor is in the Editor pane,
  323.          change its shape to a crosshair."
  324.     (editorPane frame containsPoint:Cursor offset)
  325.         ifTrue:[CursorManager hair change].
  326.  
  327. deactivatePane
  328.         "If the cursor is not in the Editor pane,
  329.          change its shape to the normal pointer."
  330.     (editorPane frame containsPoint:Cursor offset)
  331.         ifFalse:[CursorManager normal change].
  332.  
  333. reframePane:aPane
  334.     aPane == editorPane
  335.         ifTrue:[^self reframeEditor:aPane frame].
  336.     aPane == imagePane
  337.         ifTrue:[^self reframeImage:aPane frame].
  338.  
  339. zoom
  340.         "Zoom/unzoom the window."
  341.     | frame |
  342.     unZoom isNil
  343.         ifTrue:[    "Zoom to full screen"
  344.             unZoom := topPane frame.
  345.             frame  := Display boundingBox]
  346.         ifFalse:[
  347.             frame  := unZoom.
  348.             unZoom := nil].
  349.     CursorManager execute change.
  350.     topPane reframe:frame.
  351.     Scheduler resume.
  352.  
  353. close
  354.         "Prepare for closing the window."
  355.     self saved
  356.         ifFalse:[self saveIcon].
  357.     self release.
  358.  
  359. label
  360.         "Answer the window's label."
  361.     ^'IconEditor (Ver 2.1 - 07/24/90 - KEA)'.
  362.  
  363. collapsedLabel
  364.         "Answer the window's label when collapsed."
  365.     ^'IconEditor'.
  366.  
  367. "---------------------------------------"
  368. "-- List-pane menu processing methods --"
  369. "---------------------------------------"
  370.  
  371. createIt
  372.         "Create a new icon to edit."
  373.     self saved
  374.         ifTrue:[
  375.             self
  376.                 eraseImage;
  377.                 newIcon:self getIcon].
  378.  
  379. resizeIt
  380.         "Change the size of the icon."
  381.     | selection size |
  382.     self saved ifFalse:[^self].
  383.     selection := (Menu
  384.                     labels: '8@8\16@16\32@32\64@64' withCrs
  385.                     lines: #()
  386.                     selectors:#(small medium large xLarge))
  387.                         popUpAt:Cursor offset.
  388.     selection isNil ifTrue:[^self].
  389.     selection == #small  ifTrue:[size := 8@8].
  390.     selection == #medium ifTrue:[size := 16@16].
  391.     selection == #large  ifTrue:[size := 32@32].
  392.     selection == #xLarge ifTrue:[size := 64@64].
  393.     self resizeIt:size.
  394.  
  395. removeIt
  396.         "Remove the selectedIcon from the
  397.          icon library."
  398.     iconLibrary removeKey:iconName ifAbsent:[].
  399.     self
  400.         eraseEditor;
  401.         eraseImage;
  402.         changed:#iconList.
  403.     selectedIcon := nil.
  404.     iconName := ''.
  405.  
  406. "-----------------------------------------"
  407. "-- Editor-pane menu processing methods --"
  408. "-----------------------------------------"
  409.  
  410. eraseIt
  411.         "Erase icon."
  412.     (Form width:IconSize x height:IconSize y)
  413.         displayAt:imagePen clipRect origin rule:Form over.
  414.     (Form width:IconSize x * scale height:IconSize y * scale)
  415.         displayAt:editorPen clipRect origin rule:Form over.
  416.     gridForm
  417.         displayAt:editorPen clipRect origin rule:Form andRule.
  418.     self
  419.         border:editorPen clipRect
  420.             width:2
  421.             marksAt:(4 * scale).
  422.     self
  423.         border:imagePen clipRect
  424.             width:2
  425.             marksAt:0.
  426.  
  427. invertIt
  428.         "Invert the color of the icon."
  429.     selectedIcon := self getIcon reverse.
  430.     self displayIcon:selectedIcon.
  431.     saved := false.
  432.  
  433. borderIt
  434.         "Draw a border around the icon."
  435.     | inset |
  436.     (inset := Prompter prompt:'Inset?' default:'0') isNil
  437.         ifTrue:[^self].
  438.     Display border:(imagePen clipRect insetBy:inset asInteger).
  439.     self newIcon:self getIcon.
  440.     saved := false.
  441.  
  442. saveIt
  443.         "Save the new icon image."
  444.     self saveIcon.
  445.     self changed:#iconList.
  446.     listPane restoreSelected:iconName.
  447.     self activatePane.
  448.  
  449. printIcon
  450.         "Print the magnified icon from the editor pane."
  451.     CursorManager execute change.
  452.     (Form fromDisplay:(editorPen clipRect expandBy:4))
  453.         outputToPrinterUpright.
  454.     CursorManager normal change.
  455.  
  456. printWindow
  457.         "Print an image of the entire editor window."
  458.     CursorManager execute change.
  459.     (Form fromDisplay:topPane frame) outputToPrinterUpright.
  460.     CursorManager normal change.
  461.  
  462. "-----------------------------"
  463. "-- Display support methods --"
  464. "-----------------------------"
  465.  
  466. border:aRect width:aWid marksAt:aStep
  467.         "Draw a border, of width aWid, around aRect
  468.          with ruler marks ever aStep cells."
  469.     | box aForm orig wid hgt |
  470.     box := aRect expandBy:aWid.
  471.     0 to: aWid - 1 do:[:inset|
  472.         Display border:(box insetBy:inset)].
  473.     (aStep = 0)
  474.         ifTrue: ["** No ruler marks!!!! **"  ^nil].
  475.     aForm := (Form width:aWid height:aWid) reverse.
  476.     orig := aRect origin.
  477.     wid := aRect width.
  478.     hgt := aRect height.
  479.     0 to:wid by:aStep do:[:x|
  480.         aForm
  481.             displayAt:(orig + (x @ ((aWid * 2) negated)));
  482.             displayAt:(orig + (x @ (hgt + aWid)))].
  483.     0 to:hgt by:aStep do:[:y|
  484.         aForm
  485.             displayAt:(orig + (((aWid * 2) negated) @ y));
  486.             displayAt:(orig + ((wid + aWid) @ y))].
  487.  
  488. editorBorder
  489.         "Draw the ruled border around the editor frame."
  490.     self
  491.         border:editorPen clipRect
  492.         width:2
  493.         marksAt:(4 * scale).
  494.  
  495. imageBorder
  496.         "Draw the solid border around the image frame."
  497.     self
  498.         border:imagePen clipRect
  499.         width:2
  500.         marksAt:0.
  501.  
  502. displayIcon
  503.         "Display the selectedIcon for editing."
  504.     selectedIcon isNil
  505.         ifFalse:[ self displayIcon:selectedIcon].
  506.  
  507. displayIcon:anIcon
  508.         "Display anIcon for editing."
  509.     CursorManager execute change.
  510.     self
  511.         eraseImage;
  512.         displayImage:anIcon;
  513.         eraseEditor;
  514.         editorBorder;
  515.         displayEditor:anIcon.
  516.     CursorManager normal change.
  517.     self activatePane.
  518.  
  519. displayEditor:anIcon
  520.         "Display anIcon in the editor pane."
  521.     | mask |
  522.     (anIcon
  523.         magnify:(0 @ 0 extent:anIcon extent)
  524.             by:scale @ scale)
  525.         displayAt:editorPen clipRect origin
  526.             rule:Form over.
  527.     mask := gridForm deepCopy reverse.
  528.     scale > 4
  529.         ifTrue:[
  530.             mask
  531.                 displayOn:Display
  532.                     at:(editorPen clipRect origin moveBy:(1@1))
  533.                     clippingBox:editorPen clipRect
  534.                     rule:Form orThru
  535.                     mask:Form white].
  536.     mask displayOn:Display
  537.             at:(editorPen clipRect origin moveBy:(-1 @ -1))
  538.             clippingBox:editorPen clipRect
  539.             rule:Form orThru
  540.             mask:Form white.
  541.     gridForm
  542.         displayAt:editorPen clipRect origin
  543.             rule:Form andRule.
  544.  
  545.  displayImage:anIcon
  546.         "Display anIcon in the image pane."
  547.     anIcon
  548.         displayAt:imagePen clipRect origin
  549.             rule:Form over.
  550.  
  551. eraseEditor
  552.         "Erase the editor pane."
  553.     Display white:editorPane frame.
  554.  
  555. eraseImage
  556.         "Erase the image pane."
  557.     Display white:imagePane frame.
  558.  
  559. getIcon
  560.         "Answer the currently displayed icon
  561.          taken from the image pane."
  562.     ^((Form fromDisplay:imagePen clipRect)
  563.         offset:0 @ 0;
  564.         yourself).
  565.  
  566. "-----------------------------"
  567. "-- Editing support methods --"
  568. "-----------------------------"
  569.  
  570. setX:x Y:y
  571.         "Reverse a cell in both the Editor and
  572.          Icon Image panes."
  573.     editorPen
  574.         place:(self editorCellX:x y:y);
  575.         copyBits.
  576.     imagePen
  577.         place:(self imageCellX:x y:y);
  578.         copyBits.
  579.  
  580. editorCellX:x y:y
  581.         "Answer a Point with the location of the cell at
  582.          position x,y within the editor image."
  583.     ^editorPen clipRect origin
  584.         + ((x * scale @ (y * scale)) + cellOffset).
  585.  
  586. imageCellX:x y:y
  587.         "Answer a Point with the location of the cell at
  588.          position x,y within the image form."
  589.     ^imagePen clipRect origin + (x @ y).
  590.  
  591. "-------------------------------"
  592. "-- Reframing support methods --"
  593. "-------------------------------"
  594.  
  595. reframeEditor:aFrame
  596.         "Reframe the editor pane to aFrame."
  597.     | w h yScale xScale penRect size |
  598.     w := aFrame width.
  599.     h := aFrame height.
  600.     xScale := w // (IconSize x + 2).
  601.     yScale := h // (IconSize y + 2).
  602.     scale  := xScale min:yScale.
  603.     scale > 4
  604.         ifTrue:[
  605.             cellSize := (scale - 3) @ (scale - 3).
  606.             cellOffset := 2 @ 2]
  607.         ifFalse:[
  608.             cellSize := (scale - 2) @ (scale - 2).
  609.             cellOffset := 1 @ 1].
  610.     size := IconSize * scale.
  611.     gridForm := Form width:size x height:size y.
  612.     (Pen new:gridForm) grid:scale.
  613.     penRect := editorPane frame center - (size // 2) extent:size.
  614.     editorPen
  615.         clipRect:penRect;
  616.         defaultNib:cellSize;
  617.         combinationRule:Form reverse;
  618.         mask:nil.
  619.  
  620. reframeImage:aFrame
  621.         "Reframe the window's icon image pane to aFrame."
  622.     imagePen
  623.         clipRect:(aFrame center - (IconSize // 2)
  624.                     extent:IconSize);
  625.         defaultNib:1 @ 1;
  626.         combinationRule:Form reverse;
  627.         mask:nil.
  628.  
  629. "-----------------------------"
  630. "-- General support methods --"
  631. "-----------------------------"
  632.  
  633. resizeIt:aSize
  634.         "Change the size of the icon to be aSize."
  635.     aSize = IconSize ifTrue:[^self].
  636.     (selectedIcon notNil
  637.             and:[selectedIcon extent ~= aSize])
  638.         ifTrue:[
  639.             selectedIcon := nil.
  640.             iconName := String new.
  641.             self
  642.                 eraseEditor;
  643.                 eraseImage.
  644.             listPane restoreSelected:iconName].
  645.     IconSize := aSize.
  646.     topPane reframe:topPane frame.
  647.     Scheduler resume.
  648.  
  649. saved
  650.         "If the image has not changed answer true;
  651.          otherwise ask user if changes are to be lost."
  652.     saved ifTrue:[^true].
  653.     (Menu message:'Image has changed -- discard changes?') isNil
  654.         ifTrue:[^false].
  655.     saved := true.
  656.     ^saved.
  657.  
  658. saveIcon
  659.         "Save a modified icon image."
  660.     |name|
  661.     (name := Prompter
  662.                 prompt: 'Enter name of new icon'
  663.                 default: iconName) isNil
  664.         ifTrue:[^self].
  665.     (iconLibrary includesKey:name)
  666.         ifTrue:[
  667.             (Menu message:name, ' exists -- overwrite it?') isNil
  668.                 ifTrue:[^self].
  669.             iconLibrary removeKey:name].
  670.     selectedIcon := self getIcon.
  671.     iconName := name.
  672.     iconLibrary at:name put:selectedIcon.
  673.     saved := true.
  674.  
  675. "----------------------------"
  676. "-- Initialization methods --"
  677. "----------------------------"
  678.  
  679. initLibrary
  680.         "Get the icon library to use."
  681.     (Smalltalk includesKey:#IconLibrary)
  682.         ifTrue:[
  683.             iconLibrary := Smalltalk at:#IconLibrary]
  684.         ifFalse:[
  685.             iconLibrary := Dictionary new.
  686.             Smalltalk at:#IconLibrary put:iconLibrary].
  687.  
  688. newIcon:anIcon
  689.         "Set up the editor and display a new icon."
  690.     selectedIcon := anIcon deepCopy.
  691.     self displayIcon.
  692.  
  693.  
  694. [Listing -- Modified open Method]
  695.  
  696. openIt
  697.         "Open an IconEditor window."
  698.     | frame listWid listHgt |
  699.     iconLibrary isNil
  700.         ifTrue:[self initLibrary].
  701.     iconName  := String new.
  702.     saved     := true.
  703.     editorPen := Pen new.
  704.     imagePen  := Pen new.
  705.     frame     := (Display boundingBox extent // 6)
  706.                     extent:(Display boundingBox extent * 2 // 3).
  707.     listWid   := SysFont width * 10.
  708.     listHgt   := SysFont height * 10.
  709.     topPane := TopPane new
  710.         label:self label;
  711.         model:self;
  712.         menu:#windowMenu;
  713.         minimumSize:frame extent;
  714.         yourself.
  715.     topPane addSubpane:
  716.         (listPane := ListPane new
  717.             model:self;
  718.             name:#iconList;
  719.             change:#iconSelection:;
  720.             returnIndex:false;
  721.             menu:#listMenu;
  722.             framingBlock:[:aFrame|
  723.                 aFrame origin
  724.                     extent:listWid @ listHgt];
  725.             yourself).
  726.     topPane addSubpane:
  727.         (imagePane := GraphPane new
  728.             model:self;
  729.             name:#initImage:;
  730.             menu:#noMenu;
  731.             framingBlock:[:aFrame|
  732.                 aFrame origin + (0 @ listHgt)
  733.                     extent:(listWid
  734.                             @ (aFrame height - listHgt))];
  735.             yourself).
  736.     topPane addSubpane:
  737.         (editorPane := GraphPane new
  738.             model:self;
  739.             name:#initEditor:;
  740.             menu:#editorMenu;
  741.             change:#editIcon:;
  742.             framingBlock:[:aFrame|
  743.                 aFrame origin + (listWid @ 0)
  744.                     extent:((aFrame width - listWid)
  745.                             @ aFrame height)];
  746.             yourself).
  747.     topPane reframe:frame.
  748.     topPane dispatcher openWindow scheduleWindow.
  749.  
  750.